#include <tofino/constants.p4>
#include <tofino/intrinsic_metadata.p4>
#include <tofino/primitives.p4>
#include <tofino/pktgen_headers.p4>
#include <tofino/stateful_alu_blackbox.p4>
#include <tofino/wred_blackbox.p4>

#include "includes/headers.p4"
#include "includes/parser.p4"
#include "includes/macro.p4"
#include "includes/tofino.p4"

#define BUFFER_SIZE 1024
#define BUFFER_MASK 0x3ff
#define T_MAX 1000

//********//
// common actions
action nop() {
}

//**********//
// the state transferred from the ingress to the egress
header_type state_t {
	fields {
		// the following fields are from the A ring buffer of the ingress
		srcip: 32;
		dstip: 32;
		srcport: 16;
		dstport: 16;
		protocol: 8;
		count: 32;
		seq_number: 32;
		index: 32;
		new_batch: 4;
		a1_predicate: 4;
		a2_predicate: 4;
		// the following fields with the suffix of *_tmp are from 
		// the state field of the A1 of the egress
		a1_srcip: 32;
		a1_dstip: 32;
		a1_srcport: 16;
		a1_dstport: 16;
		a1_protocol: 8;
		a1_count: 32;
		a1_state_seq: 32;
		a1_state_srcip: 32;
		a1_state_dstip: 32;
		a1_state_srcport: 16;
		a1_state_dstport: 16;
		a1_state_protocol: 8;
		a1_state_count: 32;
		// the following fields are for the intermediate results 
		tmp_srcip: 32;
		tmp_dstip: 32;
		tmp_srcport: 16;
		tmp_dstport: 16;
		tmp_protocol: 8;
		tmp_count: 32;
		// the following fields with the suffix of *_tmp are from 
		// the state field of the A1 of the egress
		a2_srcip: 32;
		a2_dstip: 32;
		a2_srcport: 16;
		a2_dstport: 16;
		a2_protocol: 8;
		a2_count: 32;
		a2_state_seq: 32;
		a2_state_srcip: 32;
		a2_state_dstip: 32;
		a2_state_srcport: 16;
		a2_state_dstport: 16;
		a2_state_protocol: 8;
		a2_state_count: 32;
	    // the following fields are for the lost packet to be recovered
		lost_srcip: 32;
		lost_dstip: 32;
		lost_srcport: 16;
		lost_dstport: 16;
		lost_protocol: 8;
		lost_count: 32;
	}
}

metadata state_t state;
// registers for the ingress
register seq_number {
	width: 32;
	instance_count: 1;
}


register ingress_a_srcip // A.srcip and A.dstip in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register ingress_a_dstip // A.srcip and A.dstip in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register ingress_a_srcport // A.srcport and A.dstport in ingress
{
	width: 16;
	instance_count: BUFFER_SIZE;
}

register ingress_a_dstport // A.srcport and A.dstport in ingress
{
	width: 16;
	instance_count: BUFFER_SIZE;
}

register ingress_a_protocol // A.protocol in ingress
{
	width: 8;
	instance_count: BUFFER_SIZE;
}

register ingress_a_count // A.protocol in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

//****************************//
// registers for the egress
register egress_batch_delimiter // A.srcip and A.dstip in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

//##########################//
register egress_a1_srcip // A.srcip and A.dstip in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a1_dstip // A.srcip and A.dstip in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a1_srcport // A.srcport and A.dstport in ingress
{
	width: 16;
	instance_count: BUFFER_SIZE;
}

register egress_a1_dstport // A.srcport and A.dstport in ingress
{
	width: 16;
	instance_count: BUFFER_SIZE;
}

register egress_a1_protocol // A.protocol in ingress
{
	width: 8;
	instance_count: BUFFER_SIZE;
}

register egress_a1_count // A.protocol in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a1_state_seq // A.srcip and A.dstip in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a1_state_srcip // A.srcip and A.dstip in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a1_state_dstip // A.srcip and A.dstip in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a1_state_srcport // A.srcport and A.dstport in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a1_state_dstport // A.srcport and A.dstport in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a1_state_protocol // A.protocol in ingress
{
	width: 8;
	instance_count: BUFFER_SIZE;
}

register egress_a1_state_count // A.protocol in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

//##########################//
register egress_a2_srcip // A.srcip and A.dstip in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a2_dstip // A.srcip and A.dstip in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a2_srcport // A.srcport and A.dstport in ingress
{
	width: 16;
	instance_count: BUFFER_SIZE;
}

register egress_a2_dstport // A.srcport and A.dstport in ingress
{
	width: 16;
	instance_count: BUFFER_SIZE;
}

register egress_a2_protocol // A.protocol in ingress
{
	width: 8;
	instance_count: BUFFER_SIZE;
}

register egress_a2_count // A.protocol in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a2_state_seq // A.srcip and A.dstip in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a2_state_srcip // A.srcip and A.dstip in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a2_state_dstip // A.srcip and A.dstip in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

register egress_a2_state_srcport // A.srcport and A.dstport in ingress
{
	width: 16;
	instance_count: BUFFER_SIZE;
}

register egress_a2_state_dstport // A.srcport and A.dstport in ingress
{
	width: 16;
	instance_count: BUFFER_SIZE;
}
register egress_a2_state_protocol // A.protocol in ingress
{
	width: 8;
	instance_count: BUFFER_SIZE;
}

register egress_a2_state_count // A.protocol in ingress
{
	width: 32;
	instance_count: BUFFER_SIZE;
}

//****************************//
// generate the sequence numbers
blackbox stateful_alu generate_seq_number_bb
{
    reg: seq_number;
    update_lo_1_value: register_lo + 1;
    output_value: register_lo;
    output_dst: state.seq_number;
}

action generate_seq_number_action()
{
    generate_seq_number_bb.execute_stateful_alu();
}

table generate_seq_number_tbl {
	actions {
		generate_seq_number_action;
	}
	default_action: generate_seq_number_action;
}

//********************//
// generate an index from the sequence number 
action generate_index_action () {
	modify_field(state.index, state.seq_number, BUFFER_MASK);
}

table generate_index_tbl {
	actions {
		generate_index_action;
	}
	default_action: generate_index_action;
}

//*******************//
// update the A table in the ingress
blackbox stateful_alu ingress_srcip_xor_bb {
	reg: ingress_a_srcip;
	update_lo_1_value: 	register_lo ^ ipv4.srcip; 
	output_value: alu_lo;
	output_dst: state.srcip;	  
}


blackbox stateful_alu ingress_dstip_xor_bb {
	reg: ingress_a_dstip;
	update_lo_1_value: 	register_lo ^ ipv4.dstip; 
	output_value: alu_lo;
	output_dst: state.dstip;
}


blackbox stateful_alu ingress_srcport_xor_bb {
	reg: ingress_a_srcport;
	update_lo_1_value: 	register_lo ^ tcp.srcport; 
	output_value: alu_lo;
	output_dst: state.srcport;
}


blackbox stateful_alu ingress_dstport_xor_bb {
	reg: ingress_a_dstport;
	update_lo_1_value: 	register_lo ^ tcp.dstport; 
	output_value: alu_lo;
	output_dst: state.dstport;
}

blackbox stateful_alu ingress_protocol_xor_bb {
	reg: ingress_a_protocol;
	update_lo_1_value: 	register_lo ^ ipv4.proto; 
	output_value: alu_lo;
	output_dst: state.protocol;
}

blackbox stateful_alu ingress_count_xor_bb {
	reg: ingress_a_count;
	update_lo_1_value: 	register_lo + 1; 
	output_value: alu_lo;
	output_dst: state.count;
}


action ingress_srcip_xor_action()
{
    ingress_srcip_xor_bb.execute_stateful_alu(state.index);
}

table ingress_srcip_xor_tbl {
	actions {
		ingress_srcip_xor_action;
	}
	default_action: ingress_srcip_xor_action;
}

action ingress_dstip_xor_action()
{
    ingress_dstip_xor_bb.execute_stateful_alu(state.index);
}

table ingress_dstip_xor_tbl {
	actions {
		ingress_dstip_xor_action;
	}
	default_action: ingress_dstip_xor_action;
}

action ingress_srcport_xor_action()
{
    ingress_srcport_xor_bb.execute_stateful_alu(state.index);
}

table ingress_srcport_xor_tbl {
	actions {
		ingress_srcport_xor_action;
	}
	default_action: ingress_srcport_xor_action;
}

action ingress_dstport_xor_action()
{
    ingress_dstport_xor_bb.execute_stateful_alu(state.index);
}

table ingress_dstport_xor_tbl {
	actions {
		ingress_dstport_xor_action;
	}
	default_action: ingress_dstport_xor_action;
}


action ingress_protocol_xor_action()
{
    ingress_protocol_xor_bb.execute_stateful_alu(state.index);
}

table ingress_protocol_xor_tbl {
	actions {
		ingress_protocol_xor_action;
	}
	default_action: ingress_protocol_xor_action;
}


action ingress_count_xor_action()
{
    ingress_count_xor_bb.execute_stateful_alu(state.index);
}

table ingress_count_xor_tbl {
	actions {
		ingress_count_xor_action;
	}
	default_action: ingress_count_xor_action;
}

//********************//
// update the batch delimiter
blackbox stateful_alu update_batch_delimiter_bb {
	reg: egress_batch_delimiter;
	condition_lo: intrinsic_metadata.enq_timestamp >= register_lo + T_MAX;
	condition_hi: intrinsic_metadata.enq_timestamp < register_lo;
	update_lo_1_predicate: condition_lo;
	update_lo_1_value: intrinsic_metadata.enq_timestamp;
	output_dst: state.new_batch;
	output_value: predicate;
}

action update_batch_delimiter_action () {
    update_batch_delimiter_bb.execute_stateful_alu(state.index);
}

table update_batch_delimiter_tbl {
	actions {
		update_batch_delimiter_action;
	}
	default_action: update_batch_delimiter_action;
}

//**********//
// update the sequence number of the state field of the ring buffer A1
blackbox stateful_alu rewrite_egress_a1_state_seq_bb {
	reg: egress_a1_state_seq;
	update_lo_1_value: state.seq_number;
}

action rewrite_egress_a1_state_seq_action () {
    rewrite_egress_a1_state_seq_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu update_egress_a1_state_seq_bb {
	reg: egress_a1_state_seq;
	condition_lo: state.seq_number > register_lo;
	update_lo_1_predicate: condition_lo;
	update_lo_1_value: state.seq_number;
	output_value: predicate;
	output_dst: state.a1_predicate;
}

action update_egress_a1_state_seq_action () {
    update_egress_a1_state_seq_bb.execute_stateful_alu(state.index);
}

table update_egress_a1_state_seq_tbl {
	reads {
		state.new_batch: exact;
	}
	actions {
		update_egress_a1_state_seq_action;
		rewrite_egress_a1_state_seq_action;
		nop;
	}
}

//**********//
// update five tuples and packet count of the state field in the A1 ring buffer
blackbox stateful_alu update_egress_a1_state_srcip_bb
{
    reg: egress_a1_state_srcip;
    update_lo_1_value: state.srcip;
    output_value: register_lo;
    output_dst: state.a1_state_srcip;
}

action update_egress_a1_state_srcip_action () {
    update_egress_a1_state_srcip_bb.execute_stateful_alu(state.index);
}

table update_egress_a1_state_srcip_tbl {
	reads {
		state.new_batch: exact;
		state.a1_predicate: exact;
	}
	actions {
		update_egress_a1_state_srcip_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a1_state_dstip_bb
{
    reg: egress_a1_state_dstip;
    update_lo_1_value: state.dstip;
    output_value: register_lo;
    output_dst: state.a1_state_dstip;
}

action update_egress_a1_state_dstip_action () {
    update_egress_a1_state_dstip_bb.execute_stateful_alu(state.index);
}

table update_egress_a1_state_dstip_tbl {
	reads {
		state.new_batch: exact;
		state.a1_predicate: exact;
	}
	actions {
		update_egress_a1_state_dstip_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a1_state_srcport_bb
{
    reg: egress_a1_state_srcport;
    update_lo_1_value: state.srcport;
    output_value: register_lo;
    output_dst: state.a1_state_srcport;
}

action update_egress_a1_state_srcport_action () {
    update_egress_a1_state_srcport_bb.execute_stateful_alu(state.index);
}

table update_egress_a1_state_srcport_tbl {
	reads {
		state.new_batch: exact;
		state.a1_predicate: exact;
	}
	actions {
		update_egress_a1_state_srcport_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a1_state_dstport_bb
{
    reg: egress_a1_state_dstport;
    update_lo_1_value: state.dstport;
    output_value: register_lo;
    output_dst: state.a1_state_dstport;
}

action update_egress_a1_state_dstport_action () {
    update_egress_a1_state_dstport_bb.execute_stateful_alu(state.index);
}

table update_egress_a1_state_dstport_tbl {
	reads {
		state.new_batch: exact;
		state.a1_predicate: exact;
	}
	actions {
		update_egress_a1_state_dstport_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a1_state_protocol_bb
{
    reg: egress_a1_state_protocol;
    update_lo_1_value: state.protocol;
    output_value: register_lo;
    output_dst: state.a1_state_protocol;
}

action update_egress_a1_state_protocol_action () {
    update_egress_a1_state_protocol_bb.execute_stateful_alu(state.index);
}

table update_egress_a1_state_protocol_tbl {
	reads {
		state.new_batch: exact;
		state.a1_predicate: exact;
	}
	actions {
		update_egress_a1_state_protocol_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a1_state_count_bb
{
    reg: egress_a1_state_count;
    update_lo_1_value: state.count;
    output_value: register_lo;
    output_dst: state.a1_state_count;
}

action update_egress_a1_state_count_action () {
    update_egress_a1_state_count_bb.execute_stateful_alu(state.index);
}

table update_egress_a1_state_count_tbl {
	reads {
		state.new_batch: exact;
		state.a1_predicate: exact;
	}
	actions {
		update_egress_a1_state_count_action;
		nop;
	}
}

//**********//
// update the five tuples and packet count of the A1 of egress
blackbox stateful_alu update_egress_a1_srcip_bb
{
    reg: egress_a1_srcip;
	condition_lo: state.new_batch == 2; // this is for a new batch
	condition_hi: state.new_batch == 0; // this is for the current batch
	update_lo_1_predicate: condition_lo;
    update_lo_1_value: ipv4.srcip;
	update_lo_2_predicate: condition_hi;
	update_lo_2_value: register_lo ^ ipv4.srcip;
    output_value: register_lo;
    output_dst: state.a1_srcip;
}

action update_egress_a1_srcip_action () {
    update_egress_a1_srcip_bb.execute_stateful_alu(state.index);
}

table update_egress_a1_srcip_tbl {
	actions {
		update_egress_a1_srcip_action;
	}
	default_action: update_egress_a1_srcip_action;
}

blackbox stateful_alu update_egress_a1_dstip_bb
{
    reg: egress_a1_dstip;
	condition_lo: state.new_batch == 2; // this is for a new batch
	condition_hi: state.new_batch == 0; // this is for the current batch
	update_lo_1_predicate: condition_lo;
    update_lo_1_value: ipv4.dstip;
	update_lo_2_predicate: condition_hi;
	update_lo_2_value: register_lo ^ ipv4.dstip;
    output_value: register_lo;
    output_dst: state.a1_dstip;
}

action update_egress_a1_dstip_action () {
    update_egress_a1_dstip_bb.execute_stateful_alu(state.index);
}

table update_egress_a1_dstip_tbl {
	actions {
		update_egress_a1_dstip_action;
	}
	default_action: update_egress_a1_dstip_action;
}

blackbox stateful_alu update_egress_a1_srcport_bb
{
    reg: egress_a1_srcport;
	condition_lo: state.new_batch == 2; // this is for a new batch
	condition_hi: state.new_batch == 0; // this is for the current batch
	update_lo_1_predicate: condition_lo;
    update_lo_1_value: tcp.srcport;
	update_lo_2_predicate: condition_hi;
	update_lo_2_value: register_lo ^ tcp.srcport;
    output_value: register_lo;
    output_dst: state.a1_srcport;
}

action update_egress_a1_srcport_action () {
    update_egress_a1_srcport_bb.execute_stateful_alu(state.index);
}

table update_egress_a1_srcport_tbl {
	actions {
		update_egress_a1_srcport_action;
	}
	default_action: update_egress_a1_srcport_action;
}

blackbox stateful_alu update_egress_a1_dstport_bb
{
    reg: egress_a1_dstport;
	condition_lo: state.new_batch == 2; // this is for a new batch
	condition_hi: state.new_batch == 0; // this is for the current batch
	update_lo_1_predicate: condition_lo;
    update_lo_1_value: tcp.dstport;
	update_lo_2_predicate: condition_hi;
	update_lo_2_value: register_lo ^ tcp.dstport;
    output_value: register_lo;
    output_dst: state.a1_dstport;
}

action update_egress_a1_dstport_action () {
    update_egress_a1_dstport_bb.execute_stateful_alu(state.index);
}

table update_egress_a1_dstport_tbl {
	actions {
		update_egress_a1_dstport_action;
	}
	default_action: update_egress_a1_dstport_action;
}

blackbox stateful_alu update_egress_a1_protocol_bb
{
    reg: egress_a1_protocol;
	condition_lo: state.new_batch == 2; // this is for a new batch
	condition_hi: state.new_batch == 0; // this is for the current batch
	update_lo_1_predicate: condition_lo;
    update_lo_1_value: ipv4.proto;
	update_lo_2_predicate: condition_hi;
	update_lo_2_value: register_lo ^ ipv4.proto;
    output_value: register_lo;
    output_dst: state.a1_protocol;
}

action update_egress_a1_protocol_action () {
    update_egress_a1_protocol_bb.execute_stateful_alu(state.index);
}

table update_egress_a1_protocol_tbl {
	actions {
		update_egress_a1_protocol_action;
	}
	default_action: update_egress_a1_protocol_action;
}

blackbox stateful_alu update_egress_a1_count_bb
{
    reg: egress_a1_count;
	condition_lo: state.new_batch == 2; // this is for a new batch
	condition_hi: state.new_batch == 0; // this is for the current batch
	update_lo_1_predicate: condition_lo;
    update_lo_1_value: 1;
	update_lo_2_predicate: condition_hi;
	update_lo_2_value: register_lo + 1;
    output_value: register_lo;
    output_dst: state.a1_count;
}

action update_egress_a1_count_action () {
    update_egress_a1_count_bb.execute_stateful_alu(state.index);
}

table update_egress_a1_count_tbl {
	actions {
		update_egress_a1_count_action;
	}
	default_action: update_egress_a1_count_action;
}

//**********//
// update the sequence number of the state field of the ring buffer A2
blackbox stateful_alu rewrite_egress_a2_state_seq_bb {
	reg: egress_a2_state_seq;
	update_lo_1_value: state.a1_state_seq;
}

action rewrite_egress_a2_state_seq_action () {
    rewrite_egress_a2_state_seq_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu update_egress_a2_state_seq_bb {
	reg: egress_a2_state_seq;
	condition_lo: state.seq_number > register_lo;
	update_lo_1_predicate: condition_lo;
	update_lo_1_value: state.seq_number;
	output_value: predicate;
	output_dst: state.a2_predicate;
}

action update_egress_a2_state_seq_action () {
    update_egress_a2_state_seq_bb.execute_stateful_alu(state.index);
}

table update_egress_a2_state_seq_tbl {
	reads {
		state.new_batch: exact;
	}
	actions {
		update_egress_a2_state_seq_action;
		rewrite_egress_a2_state_seq_action;
		nop;
	}
}

//**********//
// update five tuples and packet count of the state field in the A2 ring buffer
blackbox stateful_alu update_egress_a2_state_srcip_bb
{
    reg: egress_a2_state_srcip;
	update_lo_1_value: state.srcip;
    output_value: register_lo;
    output_dst: state.a2_state_srcip;
}

action update_egress_a2_state_srcip_action () {
    update_egress_a2_state_srcip_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu forward_egress_a2_state_srcip_bb
{
    reg: egress_a2_state_srcip;
    update_lo_1_value: state.a1_state_srcip;
    output_value: register_lo;
    output_dst: state.a2_state_srcip;
}

action forward_egress_a2_state_srcip_action () {
    forward_egress_a2_state_srcip_bb.execute_stateful_alu(state.index);
}

table update_egress_a2_state_srcip_tbl {
	reads {
		state.new_batch: exact;
		state.a2_predicate: exact;
	}
	actions {
		update_egress_a2_state_srcip_action;
		forward_egress_a2_state_srcip_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a2_state_dstip_bb
{
    reg: egress_a2_state_dstip;
	update_lo_1_value: state.dstip;
    output_value: register_lo;
    output_dst: state.a2_state_dstip;
}

action update_egress_a2_state_dstip_action () {
    update_egress_a2_state_dstip_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu forward_egress_a2_state_dstip_bb
{
    reg: egress_a2_state_dstip;
    update_lo_1_value: state.a1_state_dstip;
    output_value: register_lo;
    output_dst: state.a2_state_dstip;
}

action forward_egress_a2_state_dstip_action () {
    forward_egress_a2_state_dstip_bb.execute_stateful_alu(state.index);
}

table update_egress_a2_state_dstip_tbl {
	reads {
		state.new_batch: exact;
		state.a2_predicate: exact;
	}
	actions {
		update_egress_a2_state_dstip_action;
		forward_egress_a2_state_dstip_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a2_state_srcport_bb
{
    reg: egress_a2_state_srcport;
	update_lo_1_value: state.srcport;
    output_value: register_lo;
    output_dst: state.a2_state_srcport;
}

action update_egress_a2_state_srcport_action () {
    update_egress_a2_state_srcport_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu forward_egress_a2_state_srcport_bb
{
    reg: egress_a2_state_srcport;
    update_lo_1_value: state.a1_state_srcport;
    output_value: register_lo;
    output_dst: state.a2_state_srcport;
}

action forward_egress_a2_state_srcport_action () {
    forward_egress_a2_state_srcport_bb.execute_stateful_alu(state.index);
}

table update_egress_a2_state_srcport_tbl {
	reads {
		state.new_batch: exact;
		state.a2_predicate: exact;
	}
	actions {
		update_egress_a2_state_srcport_action;
		forward_egress_a2_state_srcport_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a2_state_dstport_bb
{
    reg: egress_a2_state_dstport;
	update_lo_1_value: state.dstport;
    output_value: register_lo;
    output_dst: state.a2_state_dstport;
}

action update_egress_a2_state_dstport_action () {
    update_egress_a2_state_dstport_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu forward_egress_a2_state_dstport_bb
{
    reg: egress_a2_state_dstport;
    update_lo_1_value: state.a1_state_dstport;
    output_value: register_lo;
    output_dst: state.a2_state_dstport;
}

action forward_egress_a2_state_dstport_action () {
    forward_egress_a2_state_dstport_bb.execute_stateful_alu(state.index);
}

table update_egress_a2_state_dstport_tbl {
	reads {
		state.new_batch: exact;
		state.a2_predicate: exact;
	}
	actions {
		update_egress_a2_state_dstport_action;
		forward_egress_a2_state_dstport_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a2_state_protocol_bb
{
    reg: egress_a2_state_protocol;
	update_lo_1_value: state.protocol;
    output_value: register_lo;
    output_dst: state.a2_state_protocol;
}

action update_egress_a2_state_protocol_action () {
    update_egress_a2_state_protocol_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu forward_egress_a2_state_protocol_bb
{
    reg: egress_a2_state_protocol;
    update_lo_1_value: state.a1_state_protocol;
    output_value: register_lo;
    output_dst: state.a2_state_protocol;
}

action forward_egress_a2_state_protocol_action () {
    forward_egress_a2_state_protocol_bb.execute_stateful_alu(state.index);
}

table update_egress_a2_state_protocol_tbl {
	reads {
		state.new_batch: exact;
		state.a2_predicate: exact;
	}
	actions {
		update_egress_a2_state_protocol_action;
		forward_egress_a2_state_protocol_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a2_state_count_bb
{
    reg: egress_a2_state_count;
	update_lo_1_value: state.count;
    output_value: register_lo;
    output_dst: state.a2_state_count;
}

action update_egress_a2_state_count_action () {
    update_egress_a2_state_count_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu forward_egress_a2_state_count_bb
{
    reg: egress_a2_state_count;
    update_lo_1_value: state.a1_state_count;
    output_value: register_lo;
    output_dst: state.a2_state_count;
}

action forward_egress_a2_state_count_action () {
    forward_egress_a2_state_count_bb.execute_stateful_alu(state.index);
}

table update_egress_a2_state_count_tbl {
	reads {
		state.new_batch: exact;
		state.a2_predicate: exact;
	}
	actions {
		update_egress_a2_state_count_action;
		forward_egress_a2_state_count_action;
		nop;
	}
}
//**********//
// calculate the intermediate results for the state field of A2 ring buffer
action calc_tmp_fields_action () {
	bit_xor(state.tmp_srcip, state.a1_srcip, state.a2_state_srcip);
	bit_xor(state.tmp_dstip, state.a1_dstip, state.a2_state_dstip);
	bit_xor(state.tmp_srcport, state.a1_srcport, state.a2_state_srcport);
	bit_xor(state.tmp_dstport, state.a1_dstport, state.a2_state_dstport);
	bit_xor(state.tmp_protocol, state.a1_protocol, state.a2_state_protocol);
	add(state.tmp_count, state.a1_count, state.a2_state_count);
}

table calc_tmp_fields_tbl {
	actions {
		calc_tmp_fields_action;
	}
	default_action: calc_tmp_fields_action;
}

//**********//
// update the five tuples and packet count of the A2 of egress
blackbox stateful_alu update_egress_a2_srcip_bb
{
    reg: egress_a2_srcip;
	update_lo_1_value: register_lo ^ ipv4.srcip;
    output_value: register_lo;
    output_dst: state.a2_srcip;
}

action update_egress_a2_srcip_action () {
    update_egress_a2_srcip_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu forward_egress_a2_srcip_bb
{
    reg: egress_a2_srcip;
    update_lo_1_value: state.tmp_srcip;
    output_value: register_lo;
    output_dst: state.a2_srcip;
}

action forward_egress_a2_srcip_action () {
    forward_egress_a2_srcip_bb.execute_stateful_alu(state.index);
}

table update_egress_a2_srcip_tbl {
	reads {
		state.new_batch: exact;
	}
	actions {
		update_egress_a2_srcip_action;
		forward_egress_a2_srcip_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a2_dstip_bb
{
    reg: egress_a2_dstip;
	update_lo_1_value: register_lo ^ ipv4.dstip;
    output_value: register_lo;
    output_dst: state.a2_dstip;
}

action update_egress_a2_dstip_action () {
    update_egress_a2_dstip_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu forward_egress_a2_dstip_bb
{
    reg: egress_a2_dstip;
    update_lo_1_value: state.tmp_dstip;
    output_value: register_lo;
    output_dst: state.a2_dstip;
}

action forward_egress_a2_dstip_action () {
    forward_egress_a2_dstip_bb.execute_stateful_alu(state.index);
}

table update_egress_a2_dstip_tbl {
	reads {
		state.new_batch: exact;
	}
	actions {
		update_egress_a2_dstip_action;
		forward_egress_a2_dstip_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a2_srcport_bb
{
    reg: egress_a2_srcport;
	update_lo_1_value: register_lo ^ tcp.srcport;
    output_value: register_lo;
    output_dst: state.a2_srcport;
}

action update_egress_a2_srcport_action () {
    update_egress_a2_srcport_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu forward_egress_a2_srcport_bb
{
    reg: egress_a2_srcport;
    update_lo_1_value: state.tmp_srcport;
    output_value: register_lo;
    output_dst: state.a2_srcport;
}

action forward_egress_a2_srcport_action () {
    forward_egress_a2_srcport_bb.execute_stateful_alu(state.index);
}

table update_egress_a2_srcport_tbl {
	reads {
		state.new_batch: exact;
	}
	actions {
		update_egress_a2_srcport_action;
		forward_egress_a2_srcport_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a2_dstport_bb
{
    reg: egress_a2_dstport;
	update_lo_1_value: register_lo ^ tcp.dstport;
    output_value: register_lo;
    output_dst: state.a2_dstport;
}

action update_egress_a2_dstport_action () {
    update_egress_a2_dstport_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu forward_egress_a2_dstport_bb
{
    reg: egress_a2_dstport;
    update_lo_1_value: state.tmp_dstport;
    output_value: register_lo;
    output_dst: state.a2_dstport;
}

action forward_egress_a2_dstport_action () {
    forward_egress_a2_dstport_bb.execute_stateful_alu(state.index);
}

table update_egress_a2_dstport_tbl {
	reads {
		state.new_batch: exact;
	}
	actions {
		update_egress_a2_dstport_action;
		forward_egress_a2_dstport_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a2_protocol_bb
{
    reg: egress_a2_protocol;
	update_lo_1_value: register_lo ^ ipv4.proto;
    output_value: register_lo;
    output_dst: state.a2_protocol;
}

action update_egress_a2_protocol_action () {
    update_egress_a2_protocol_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu forward_egress_a2_protocol_bb
{
    reg: egress_a2_protocol;
    update_lo_1_value: state.tmp_protocol;
    output_value: register_lo;
    output_dst: state.a2_protocol;
}

action forward_egress_a2_protocol_action () {
    forward_egress_a2_protocol_bb.execute_stateful_alu(state.index);
}

table update_egress_a2_protocol_tbl {
	reads {
		state.new_batch: exact;
	}
	actions {
		update_egress_a2_protocol_action;
		forward_egress_a2_protocol_action;
		nop;
	}
}

blackbox stateful_alu update_egress_a2_count_bb
{
    reg: egress_a2_count;
	update_lo_1_value: register_lo + 1;
    output_value: register_lo;
    output_dst: state.a2_count;
}

action update_egress_a2_count_action () {
    update_egress_a2_count_bb.execute_stateful_alu(state.index);
}

blackbox stateful_alu forward_egress_a2_count_bb
{
    reg: egress_a2_count;
    update_lo_1_value: state.tmp_count;
    output_value: register_lo;
    output_dst: state.a2_count;
}

action forward_egress_a2_count_action () {
    forward_egress_a2_count_bb.execute_stateful_alu(state.index);
}

table update_egress_a2_count_tbl {
	reads {
		state.new_batch: exact;
	}
	actions {
		update_egress_a2_count_action;
		forward_egress_a2_count_action;
		nop;
	}
}

//**********//
// recover the lost packet
action recover_lost_packet_action () {
	bit_xor(state.lost_srcip, state.a2_state_srcip, state.a2_srcip);
	bit_xor(state.lost_dstip, state.a2_state_dstip, state.a2_dstip);
	bit_xor(state.lost_srcport, state.a2_state_srcport, state.a2_srcport);
	bit_xor(state.lost_dstport, state.a2_state_dstport, state.a2_dstport);
	bit_xor(state.lost_protocol, state.a2_state_protocol, state.a2_protocol);
	subtract(state.lost_count, state.a2_state_count, state.a2_count);
}

table recover_lost_packet_tbl {
  reads {
  state.new_batch: exact;
  }
	actions {
	  recover_lost_packet_action;
	}
	default_action: recover_lost_packet_action;
}



//**********//
field_list flow {
    ipv4.srcip;
    ipv4.dstip;
    ipv4.proto;
    tcp.srcport;
    tcp.dstport;
}

// for the calculation of the index of the filter of the ingress sketch
field_list_calculation filter_idx_hash {
    input {
        flow;
    }
    algorithm: crc32;
    output_width: INGRESS_SKETCH_IDX_WIDTH;
}

// for the calculation of the index of the row 1 of the ingress sketch
field_list_calculation is_row1_idx_hash {
    input {
        flow;
    }
    algorithm: crc32_extend;
    output_width: INGRESS_SKETCH_IDX_WIDTH;
}

// for the calculation of the index of the row 2 of the ingress sketch
field_list_calculation is_row2_idx_hash {
    input {
        flow;
    }
    algorithm: crc32_lsb;
    output_width: INGRESS_SKETCH_IDX_WIDTH;
}

field_list_calculation fingerprint_hash {
    input {
        flow;
    }
    algorithm: identity;
    output_width: FINGERPRINT_WIDTH;
}



action set_egr(egress_spec) {
	modify_field(ig_intr_md_for_tm.ucast_egress_port, egress_spec);
}

//new added by ying
 action set_dip(egress_spec){
 	modify_field(ethernet.dstAddr, 194114530791924);
 	modify_field(ipv4.dstip, 3232236033);
 	modify_field(ig_intr_md_for_tm.ucast_egress_port, egress_spec);
 }
 
 
@pragma stage 0
table forward {
	reads {
		ig_intr_md.ingress_port: exact;
	}
	actions {
		set_egr; nop; set_dip;
	}
}


register timestamp_arrival // the local time when a packet comes in
{
	width: 32;
	instance_count: 1024;
}

register timestamp_sender // the timestamp carried by the arrival packets
{
	width: 32;
	instance_count: 1024;
}

blackbox stateful_alu update_timestamp_arrival
{
    reg: timestamp_arrival;
    update_lo_1_value: register_lo + 1;
    output_value: alu_lo;
//    output_dst: measurement_meta.pkt_seq_no_out;
}

blackbox stateful_alu update_timestamp_sender
{
    reg: timestamp_sender;
    update_lo_1_value: register_lo + 1;
    output_value: alu_lo;
//    output_dst: measurement_meta.npkts;
}

register pkt_seq_no_out // the local time when a packet comes in
{
	width: 32;
	instance_count: 32;
}

blackbox stateful_alu update_pkt_seq_no_out
{
    reg: pkt_seq_no_out;
    update_lo_1_value: register_lo + 1;
    output_value: alu_lo;
    output_dst: constmon.seq_no;
}

action update_pkt_seq_no_out_action()
{
    update_pkt_seq_no_out.execute_stateful_alu(ig_intr_md_for_tm.ucast_egress_port);
}

table update_pkt_seq_no_out_t
{
    actions {
        update_pkt_seq_no_out_action;
    }
    default_action: update_pkt_seq_no_out_action;
}

action add_header_action() {
	modify_field(constmon.next_header, ipv4.proto);
	modify_field(constmon.timestamp_loc, eg_intr_md_from_parser_aux.egress_global_tstamp);
	modify_field(constmon.timestamp_ret, ig_intr_md.ingress_mac_tstamp);
//	modify_field(constmon.timestamp_loc, intrinsic_metadata.egress_global_timestamp);
	modify_field(ipv4.proto, IPV4_CONSTMON);
	add_header(constmon);
}

table add_header_t {
	actions {
		add_header_action;
	}
	default_action: add_header_action;
}

control ingress
{
	// stage 0
	apply(forward); 
	// update the sequence number
	/* apply(generate_seq_number_tbl); */
	// calculate the index from the sequence number
	/* apply(generate_index_tbl); */
	// update the five tuples and the packet count of the A ring buffer
	/* apply(ingress_srcip_xor_tbl); */
	/* apply(ingress_dstip_xor_tbl); */
	/* apply(ingress_srcport_xor_tbl); */
	/* apply(ingress_dstport_xor_tbl); */
	/* apply(ingress_protocol_xor_tbl); */
	/* apply(ingress_count_xor_tbl); */
}

control egress
{
    // update the batch delimiter 
    /* apply(update_batch_delimiter_tbl); */
    /* 	// update the state field of A1 ring buffer */
    /* 	apply(update_egress_a1_state_seq_tbl); */
    /* 	apply(update_egress_a1_state_srcip_tbl); */
    /* 	apply(update_egress_a1_state_dstip_tbl); */
    /* 	apply(update_egress_a1_state_srcport_tbl); */
    /* 	apply(update_egress_a1_state_dstport_tbl); */
    /* 	apply(update_egress_a1_state_protocol_tbl); */
    /* 	apply(update_egress_a1_state_count_tbl); */
    /* 	// update the five tuples and packet count of the A1 ring buffer */
    /* 	apply(update_egress_a1_srcip_tbl); */
    /* 	apply(update_egress_a1_dstip_tbl); */
    /* 	apply(update_egress_a1_srcport_tbl); */
    /* 	apply(update_egress_a1_dstport_tbl); */
    /* 	apply(update_egress_a1_protocol_tbl); */
    /* 	apply(update_egress_a1_count_tbl); */
    /* 	// update the state field of the A2 ring buffer */
    /* 	apply(update_egress_a2_state_seq_tbl); */
    /* 	apply(update_egress_a2_state_srcip_tbl); */
    /* 	apply(update_egress_a2_state_dstip_tbl); */
    /* 	apply(update_egress_a2_state_srcport_tbl); */
    /* 	apply(update_egress_a2_state_dstport_tbl); */
    /* 	apply(update_egress_a2_state_protocol_tbl); */
    /* 	apply(update_egress_a2_state_count_tbl); */
    /* 	// update the intermediate values */
    /* 	apply(calc_tmp_fields_tbl); */
    /* 	// update the five tuples and packet count of the A2 ring buffer */
    /* 	apply(update_egress_a2_srcip_tbl); */
    /* 	apply(update_egress_a2_dstip_tbl); */
    /* 	apply(update_egress_a2_srcport_tbl); */
    /* 	apply(update_egress_a2_dstport_tbl); */
    /* 	apply(update_egress_a2_protocol_tbl); */
    /* 	apply(update_egress_a2_count_tbl); */
    /* 	// recover the flow ID of the lost packet */
    /* 	apply(recover_lost_packet_tbl); */
    /* 	//\**********\// */
    /* 	if(valid(tcp) or valid(udp)) {		// stage 0 */
    /* 		// stage 0 */
    /* 		apply(update_pkt_seq_no_out_t); */
    /* 		apply(add_header_t); */
    /* 	} */
}
